﻿
namespace HyperF.RemoteExecuter

open System
open System.Net
open System.Net.Sockets
open System.ServiceProcess


/// <summary>
/// The HyperF service to execute locally some functions that cannot be executed remotely via WMI (generally for security reasons)
/// </summary>
type HyperFService =
  inherit System.ServiceProcess.ServiceBase

  val private listener : TcpListener
  val private components : System.ComponentModel.IContainer

  new() as x =
    {
      listener = new TcpListener(IPAddress.Parse("0.0.0.0"), 17300)
      components = new System.ComponentModel.Container()
    }
    then
      x.ServiceName <- "HyperF RemoteExecuter"
           

  member private x.AcceptTcpClientCallback (ar:IAsyncResult) =
    try
      let client = x.listener.EndAcceptTcpClient(ar)

      // Open the socket stream
      use stream = client.GetStream()
      use sr = new System.IO.StreamReader(stream)
      use sw = new System.IO.StreamWriter(stream)
      sw.AutoFlush <- true

      try
        // Read the command to execute
        let functionName = sr.ReadLine()
        match functionName with
        | "get_IpAddressByMac" -> Functions.get_IpAddressByMac sr sw
        | "export_VM" -> Functions.export_VM sr sw
        | "exportEx_VM" -> Functions.exportEx_VM sr sw
        | "import_VM" -> Functions.import_VM sr sw
        | "importEx_VM" -> Functions.importEx_VM sr sw
        | "delete_VM" -> Functions.delete_VM sr sw
        | "new_VHD_Differencing" -> Functions.new_VHD_Differencing sr sw
        | "new_VHD_Dynamic" -> Functions.new_VHD_Dynamic sr sw
        | "new_VHD_Fixed" -> Functions.new_VHD_Fixed sr sw
        | "merge_VHD" -> Functions.merge_VHD sr sw
        | "get_VHDInfo" -> Functions.get_VHDInfo sr sw
        | "mount_VHD" -> Functions.mount_VHD sr sw
        | "unmount_VHD" -> Functions.unmount_VHD sr sw
        | "new_VM" -> Functions.new_VM sr sw
        | "new_VM_To" -> Functions.new_VM_To sr sw
        | "add_VMDVDDiskToController" -> Functions.add_VMDVDDiskToController sr sw
        | "add_VMHardDiskToDrive" -> Functions.add_VMHardDiskToDrive sr sw
        | "add_VMFloppyDisk" -> Functions.add_VMFloppyDisk sr sw
        | _ -> sw.WriteLine(false); sw.WriteLine(functionName + " not found")
      
      with e -> sw.WriteLine(false); sw.WriteLine(e.Message)

      client.Close()

    with _ -> ()

    x.listener.BeginAcceptTcpClient(new AsyncCallback(x.AcceptTcpClientCallback), null) |> ignore
    ()
  
  override x.OnStart (args:string array) =
    try
      x.listener.Start()
      x.listener.BeginAcceptTcpClient(new AsyncCallback(x.AcceptTcpClientCallback), null) |> ignore
    with _ -> ()

  override x.OnStop() =
    x.listener.Stop()

  member x.OnDebugStart (args:string array) = x.OnStart(args)
  member x.OnDebugStop () = x.OnStop()
    


//--------------------------------------------------------------

module Main =
  let servicesToRun : ServiceBase array = [| new HyperFService() |]
  ServiceBase.Run(servicesToRun)